#pragma once
#include "Task.hpp"
#include "Protocol.hpp"
#include <pthread.h>
#include <queue>
#define NUM 50
class ThreadPool
{
private:
    int num;
    bool stop;
    queue<Task> task_queue;
    pthread_cond_t cond;
    pthread_mutex_t lock;
    static ThreadPool *single_instance;
    ThreadPool(int Num = NUM)
        : num(Num), stop(false)
    {
        pthread_mutex_init(&lock);
        pthread_cond_init(&cond);
    }

public:
    static ThreadPool *get_instance()
    {
        static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
        if (single_instance == nullptr)
        {
            pthread_mutex_lock(&_mutex);
            if (single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&_mutex);
        }
        return single_instance;
    }
    bool IsStop()
    {
    }
    bool IsEmpty()
    {
        return task_queue.size() == 0 ? true : false;
    }
    void InitThreadPool()
    {
        pthread_t tid[num];
        for (int i = 0; i < num; i++)
        {
            pthread_create(&tid[i], nullptr, ThreadRoutine, (void *)this);
        }
    }
    static void *ThreadRoutine(void *args)
    {
        ThreadPool *tp = (ThreadPool *)args;
        while (!stop)
        {
            Task t;
            Lock();
            while (IsEmpty())
            {
                ThreadWait();
            }
            PopTask(t);
            UnLock();
            t.ProcessOn();
        }
        return nullptr;
    }
    void PushTask(const Task &task)
    {
        Lock();
        task_queue.push(task);
        ThreadWakeup();
        UnLock();
    }
    void PopTask(Task &task)
    {
        Lock();
        task = task_queue.front();
        task_queue.pop();
        UnLock();
    }
    void ThreadWait()
    {
        pthread_cond_wait(&cond, &lock);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&cond, &lock);
    }
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&lock);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
};
ThreadPool *ThreadPool::single_instance = nullptr;